using System;
using System.Linq;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using GameFramework.Localization;
using LS.UnityExtensions.Editor;
using LS.Localization;
using Type = System.Type;

namespace LS.Editor.Localization
{
    [CustomEditor(typeof(LocalizationSetting))]
    public class LocalizationSettingInspector : InspectorBase
    {
        private Vector2 m_ListScroll = Vector2.zero;

        private HashSet<Language> m_LanguageHash = new HashSet<Language>();
        private Dictionary<Language, bool> m_ToggleGroupValue = new Dictionary<Language, bool>();

        private List<TextAsset> m_TempXmlDatas = new List<TextAsset>();

        private SerializedProperty m_Collection;

        private static readonly Type m_TextAssetType = typeof(TextAsset);

        private static Dictionary<Language, GUIContent> s_LanguageGuiContentPool = new Dictionary<Language, GUIContent>();

        internal static class Contents
        {
            public static readonly GUIContent DataCount = new GUIContent("Data Count");
            public static readonly GUIContent Remove = new GUIContent("Remove");
            public static readonly GUIContent EmptyReference = new GUIContent("Reference Object is empty, it may have been deleted.");
        }

        protected override void OnEnable()
        {
            base.OnEnable();
            m_Collection = serializedObject.FindProperty("m_Collection");
            InitGuiContentPool();
            InitLanguageHashSet();
            GetLanguagePopup();
        }

        protected override void OnDisable()
        {
            base.OnDisable();
        }

        private void InitGuiContentPool()
        {
            if (s_LanguageGuiContentPool.Count > 0) return;
            var names = Enum.GetNames(typeof(Language));
            for (int i = 0; i < names.Length; i++)
            {
                Language lan = Enum.Parse<Language>(names[i]);

                if(lan != Language.Unspecified)
                    s_LanguageGuiContentPool.Add(lan, new GUIContent(names[i]));
            }
        }

        private void InitLanguageHashSet()
        {
            LocalizationSetting setting = target as LocalizationSetting;
            m_LanguageHash.Clear();
            foreach (var item in setting.Collection)
            {
                m_LanguageHash.Add(item.Language);
            }
        }

        private GUIContent[] GetLanguagePopup()
        {
            return s_LanguageGuiContentPool
                .Where(s => !m_LanguageHash.Contains(s.Key))
                .Select(s => s.Value)
                .ToArray();
        }

        public override void DrawInspectorItems()
        {
            base.DrawInspectorItems();
            this.serializedObject.Update();

            GUILayout.Label("Languages");
            GUILayout.BeginVertical("box");
            m_ListScroll = GUILayout.BeginScrollView(m_ListScroll);
            int count = m_Collection.arraySize;
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    DrawLanguageSetting(m_Collection.GetArrayElementAtIndex(i),i);
                }
            }
            GUILayout.EndScrollView();
            DrawControllerButtons();
            GUILayout.EndVertical();
        }

        public override void DrawInspectorFinish()
        {
            base.DrawInspectorFinish();
            AssetDatabase.SaveAssetIfDirty(target);
        }

        private void DrawLanguageSetting(SerializedProperty language,int index)
        {

            bool toggleValue = true;
            SerializedProperty languageProperty = language.FindPropertyRelative("m_Language");
            SerializedProperty settingProperty = language.FindPropertyRelative("m_Setting");
            Language languageType = (Language)languageProperty.enumValueFlag;

            if (settingProperty.objectReferenceValue == null)
            {
                toggleValue = EditorGUILayout.BeginFoldoutHeaderGroup(
                    toggleValue,
                    s_LanguageGuiContentPool[(Language)languageProperty.enumValueFlag],
                    menuAction: (rect) => CreateLanguageFoldoutClickMenu(rect, languageType));
                EditorGUILayout.HelpBox($"Setting of language [{languageType.ToString()}] is missing, It might be deleted. You should remove this content before you use it.", MessageType.Error);
                EditorGUILayout.EndFoldoutHeaderGroup();
            }
            else
            {
                LanguageSetting languageSetting = settingProperty.objectReferenceValue as LanguageSetting;
                m_TempXmlDatas.Clear();
                m_TempXmlDatas.AddRange(languageSetting.Datas);

                if (!m_ToggleGroupValue.TryGetValue(languageType, out toggleValue))
                {
                    toggleValue = true;
                    m_ToggleGroupValue.Add(languageType, toggleValue);
                }

                toggleValue = EditorGUILayout.BeginFoldoutHeaderGroup(
                    toggleValue,
                    s_LanguageGuiContentPool[languageType],
                    menuAction: (rect) => CreateLanguageFoldoutClickMenu(rect, languageType));

                m_ToggleGroupValue[languageType] = toggleValue;

                if (toggleValue)
                {
                    using (new EditorGUI.DisabledGroupScope(true))
                    {
                        EditorGUILayout.PropertyField(settingProperty);
                        EditorGUILayout.IntField(Contents.DataCount, m_TempXmlDatas.Count);
                        for (int i = 0; i < m_TempXmlDatas.Count; i++)
                        {
                            EditorGUILayout.ObjectField(m_TempXmlDatas[i], m_TextAssetType, false);
                        }
                    }
                }

                EditorGUILayout.EndFoldoutHeaderGroup();
            }
        }

        private void DrawControllerButtons()
        {
            if(GUILayout.Button("Add Language"))
            {
                var popupArray = GetLanguagePopup();
                var currentEvent = UnityEngine.Event.current;
                Vector2 mouseposition = currentEvent.mousePosition;
                Rect rect = new Rect(mouseposition.x, mouseposition.y, 0, 0);
                EditorUtility.DisplayCustomMenu(rect, popupArray, -1, PopupCallback, null);
            }
        }

        private void AddLanguage(Language language)
        {
            Debug.Log($"AddLanguage {language.ToString()}");
            LocalizationSetting setting = target as LocalizationSetting;
            string name = language.ToString();
            string path = AssetDatabase.GetAssetPath(this.target);
            string directory = Path.GetDirectoryName(path);
            var languageSetting = LocalizationSettingUtil.CreateOrGetLanguageSetting(language, $"{directory}/{name}/LanguageSetting-{name}.asset");

            m_LanguageHash.Add(language);
            setting.Collection.Add(new LocalizationSetting.Content(languageSetting));
            EditorUtility.SetDirty(setting);
            AssetDatabase.SaveAssetIfDirty(setting);
        }

        private void RemoveLanguage(Language language)
        {
            Debug.Log($"RemoveLanguage {language.ToString()}");
            LocalizationSetting setting = target as LocalizationSetting;
            int index = setting.Collection.FindIndex(c => c.Language == language);
            if (index >= 0)
            {
                setting.Collection.RemoveAt(index);
                m_LanguageHash.Remove(language);
                EditorUtility.SetDirty(setting);
                AssetDatabase.SaveAssetIfDirty(setting);
            }
        }
        

        private void CreateLanguageFoldoutClickMenu(Rect rect,Language language)
        {
            var menu = new GenericMenu();
            menu.AddItem(Contents.Remove, false, () => RemoveLanguage(language));
            menu.DropDown(rect);
        }

        private void PopupCallback(object userData, string[] options, int selected)
        {
            string name = options[selected];
            if (Enum.TryParse<Language>(name, false,out Language result))
            {
                AddLanguage(result);
            }
        }
    }
}
